/**
 * Licensed under the MIT License
 *
 * Copyright (c) 2010 Laurent Berthelot
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package marcel.display.screen
{
	import flash.display.DisplayObject;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import marcel.debug.*;
	
	
	/**
	 * ScreenManager class used to position and resize elements on screen compared to the stage size
	 * @author	Laurent Berthelot
	 */
	public class ScreenManager
	{
		//--------------------------------------------------------------------------
		//
		//  Private vars
		//
		//--------------------------------------------------------------------------
		/**
		 * @private
		 */
		protected var _items:/*ScreenItem*/Array = new Array();
		/**
		 * @private
		 */
		protected var _stage:Stage;
		/**
		 * @private
		 */
		protected var _enabled:Boolean = false;
		
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		/**
		 * Constructs a new ScreenManager instance
		 * @param	stage	The stage reference to get the size from
		 */
		public function ScreenManager(stage:Stage) {
			_stage = stage;
		}
		
		
		//--------------------------------------------------------------------------
		//
		//  Public methods
		//
		//--------------------------------------------------------------------------
		/**
		 * Adds a new ScreenItem to the list of items handled by the current manager
		 * @param	si	A ScreenItem instance to add
		 * @return	true if the item has been added, false if the item or its target was already in the list
		 */
		public function addItem(si:ScreenItem):Boolean {
			if (_isRegister(si)) return false;
			_items.push(si);
			if (_enabled) si.update(_stage, true);
			return true;
		}
		
		/**
		 * Removes an item from the list of items handled by the current manager
		 * @param	si	A ScreenItem instance to remove
		 * @return	true if the item has been removed, false if the item has not been found
		 */
		public function removeItem(si:ScreenItem):Boolean {
			for (var i:int = 0; i < _items.length; i++) {
				if (_items[i] == si)
				{
					_items.splice(i, 1);
					return true;
				}
			}
			return false;
		}
		
		/**
		 * Returns a screenItem instance from the target display object
		 * @param	target	the display object to get the screen item from
		 * @return	the ScreenItem instance, or null if not found
		 */
		public function getScreenItem(target:DisplayObject):ScreenItem {
			for (var i:int = 0; i < _items.length; i++) {
				if (_items[i].target == target) return _items[i];
			}
			return null;
		}
		
		/**
		 * Removes an item from the list of items handled by the current manager from its target
		 * @param	si	A target used by a ScreenItem instance to remove
		 * @return	true if the item has been removed, false if the item has not been found
		 */
		public function removeTarget(target:DisplayObject):Boolean {
			for (var i:int = 0; i < _items.length; i++) {
				if (_items[i].target == target)
				{
					_items.splice(i, 1);
					return true;
				}
			}
			return false;
		}
		
		/**
		 * Enables the current manager, meaning the items will be updated each time the stage is resized.
		 */
		public function enable():void {
			if (!_enabled)
			{
				_enabled = true;
				_stage.addEventListener(Event.RESIZE, _onResize);
				update(true);
			}
		}
		
		/**
		 * Disables the current manager, meaning items are not updated anymore.
		 */
		public function disable():void {
			if (_enabled)
			{
				_enabled = false;
				_stage.removeEventListener(Event.RESIZE, _onResize);
			}
		}
		
		/**
		 * UPdates the size and the position of all the items
		 * @param	forceNoTween	Indicates if the tween effect must not be applied, for example on the first call.
		 */
		public function update(forceNoTween:Boolean = false):void {
			for (var i:int = 0; i < _items.length; i++) _items[i].update(_stage, forceNoTween);
		}
		
		/**
		 *
		 */
		public static function getInnerRec(target : Point,  referer : Point) : Rectangle {
			return _getResizeRectangle(Math.min(referer.x / target.x, referer.y / target.y), target, referer);
		}
		
		/**
		 *
		 */
		public static function getOuterRec(target : Point, referer : Point) : Rectangle {
			return _getResizeRectangle(Math.max(referer.x / target.x, referer.y / target.y), target, referer);
		}
		
		/**
		 *
		 */
		protected static function _getResizeRectangle(ratio:Number, target:Point, referer:Point):Rectangle {
			return new Rectangle((referer.x - target.x * ratio) >> 1, (referer.y - target.y * ratio) >> 1, target.x * ratio, target.y * ratio);
		}

		
		//--------------------------------------------------------------------------
		//
		//  Private methods
		//
		//--------------------------------------------------------------------------
		private function _isTargetRegister(target:DisplayObject):Boolean {
			for (var i:int = 0; i < _items.length; i++) {
				if (_items[i].target === target) return true;
			}
			return false;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Events
		//
		//--------------------------------------------------------------------------
		private function _onResize(e:Event):void {
			update();
		}
		
		private function _isRegister(si:ScreenItem):Boolean {
			if (_items.indexOf(si) !== -1) return true;
			return _isTargetRegister(si.target);
		}
	}
}